//------------------------------------------------------------------------------
//
//   author: 小兵（aosnow@yeah.net）
//   create: 2012-5-29 下午22:36:19
//    class: SWFLoader - SWF加载类
//
//------------------------------------------------------------------------------

package starfire.rpc.loader.elements
{
	import flash.display.Loader;
	import flash.display.LoaderInfo;
	import flash.errors.EOFError;
	import flash.errors.IOError;
	import flash.events.Event;
	import flash.events.IOErrorEvent;
	import flash.events.ProgressEvent;
	import flash.events.SecurityErrorEvent;
	import flash.net.URLLoader;
	import flash.net.URLLoaderDataFormat;
	import flash.net.URLRequest;
	import flash.system.ApplicationDomain;
	import flash.system.LoaderContext;
	import flash.system.System;
	import flash.utils.ByteArray;
	
	import starfire.rpc.URL;
	import starfire.rpc.loader.LoadMessage;
	import starfire.rpc.loader.LoadState;
	import starfire.rpc.loader.MediaCache;

	[ExcludeClass]
	public class SWFLoader extends LoaderBase
	{
		protected var urlLoader:URLLoader;
		protected var loader:Loader;
		protected var context:LoaderContext;

		/** 若资源为经过处理的加密码资源，则需要设置解密方法  **/
		protected var decryption:Function;

		/**
		 * SWF加载器
		 * @param message				- 加载描述信息
		 * @param decryption			- 用于将加载后的字节数据进行解码
		 * <br><br>
		 * 若SWF源是未经加密的，可省略 decryption 解密函数的设置，函数执行时将传入一个字节数组参数，如：
		 * <p><code>
		 * function decryption(bytes:ByteArray):ByteArray<br>
		 * {<br>
		 * &nbsp;&nbsp;&nbsp; // ... 此处对 bytes 进行解密后并返回<br>
		 * &nbsp;&nbsp;&nbsp; return newBytes;<br>
		 * }<br>
		 * </code></p>
		 */
		public function SWFLoader( message:LoadMessage, decryption:Function = null )
		{
			super( message );

			this.decryption = decryption is Function ? decryption : message.decryption;
		}

		override public function canHandleResource():Boolean
		{
			if( super.message )
			{
				var url:URL = new URL( super.message.url );
				return ( url.path.search( /\.swf$|\.swfx$/i ) != -1 );
			}

			return false;
		}

		override protected function executeLoad( message:LoadMessage ):void
		{
			var urlReq:URLRequest = new URLRequest( message.url );

			/**
			 * 因为有可能被加载的SWF不再是完整的或者已经过加密处理，所以只能通过二进制下载，
			 * 再经过相应的字节解密，才能通过loader.loadBytes来获取
			 */
			urlLoader = new URLLoader();
			urlLoader.dataFormat = URLLoaderDataFormat.BINARY;
			toggleLoaderListeners( urlLoader, true );

			// SWF解析器
			loader = new Loader();
			loader.contentLoaderInfo.addEventListener( Event.COMPLETE, swfLoadCompleteHandler );

			// 安全设置
			context = new LoaderContext();

			// 设置存放域空间
			context.applicationDomain = message.domain ? message.domain : ApplicationDomain.currentDomain;
			context.allowCodeImport = true;

			// 开始加载数据
			try
			{
				updateLoadState( LoadState.LOADING );
				urlLoader.load( urlReq );
			}
			catch( ioError:IOError )
			{
				IOErrorHandler( null, ioError.message );
			}
			catch( securityError:SecurityError )
			{
				securityErrorHandler( null, securityError.message );
			}
		}

		override protected function executeUnload( message:LoadMessage ):void
		{
			updateLoadState( LoadState.UNLOADING );
			urlLoader = null;
			loader = null;
			context = null;
			updateLoadState( LoadState.UNINITIALIZED );
		}

		override protected function loadCompleteHandler( event:Event ):void
		{
			toggleLoaderListeners( urlLoader, false );

			try
			{
				var bytes:ByteArray = urlLoader.data as ByteArray;
				MediaCache.cacheByteArray( message, bytes );

				if( decryption is Function )
				{
					bytes = decryption( bytes );
				}
				loader.removeEventListener( ProgressEvent.PROGRESS, progressHandle );
				loader.addEventListener( IOErrorEvent.IO_ERROR, IOErrorHandler );
				loader.addEventListener( SecurityErrorEvent.SECURITY_ERROR, securityErrorHandler );
				loader.loadBytes( bytes, context );
			}
			catch( eofError:EOFError )
			{
				IOErrorHandler( null, eofError.message );
			}
			catch( ioError:IOError )
			{
				IOErrorHandler( null, ioError.message );
			}
			catch( securityError:SecurityError )
			{
				securityErrorHandler( null, securityError.message );
			}
		}

		private function swfLoadCompleteHandler( event:Event ):void
		{
			loader.contentLoaderInfo.removeEventListener( Event.COMPLETE, swfLoadCompleteHandler );

			// SWF 文件保存整个程序域空间
			try
			{
				// 例：访问类定义必须写完全类名 trace( data.hasDefinition( "com.dy.layout.nres.Stone" ));
				saveCache( loader );
			}
			catch( e:Error )
			{
				return;
			}

			updateLoadState( LoadState.READY );

			// 执行回调函数
			if( complete is Function )
			{
				complete( loader.contentLoaderInfo );
			}
		}
	}
}
